package com.broada.apm.indicator.api.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.es.indices.support.PerfIndicesBuilder;
import com.broada.apm.indicator.api.ErrorRecordService;
import com.broada.apm.indicator.api.common.ApmDataIndicatorException;
import com.broada.apm.indicator.api.model.SearchCondition;
import com.broada.apm.indicator.api.model.SearchConditionItem;
import com.broada.apm.indicator.api.util.AggregationUtil;
import com.broada.apm.model.ErrorRecord;
import com.broada.apm.model.ErrorRecordView;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.PerformanceView;
import com.broada.apm.model.Scope;
import com.broada.apm.utils.EsClientUtil;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.JsonUtil;

public class ErrorRecordServiceImpl implements ErrorRecordService {
	
    private static final Logger LOG = LoggerFactory.getLogger(ErrorRecordServiceImpl.class);
    private Client client = EsClientUtil.getTransportClient();
    
    /**
     * 根据组装好的查询条件过滤查询错误码
     */
    @Override
	public PagingList<ErrorRecordView> queryAggregationTermsErrorRedords(String applicationId,
			SearchCondition searchCondition) {
		PagingList<ErrorRecordView> records = new PagingList<ErrorRecordView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("错误交易查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getErrorIndices(applicationId, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return records;
			SearchRequestBuilder searchBuilder = client.prepareSearch(); // {}
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_ERRORS.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			Aggregations aggs = response.getAggregations();
			List<Map<String, Object>> aggRows = AggregationUtil.parseMultiTermsAggregations(aggs);
			for (Map<String, Object> map : aggRows) {
				ErrorRecordView er = JsonUtil.map2obj(map, ErrorRecordView.class);
				records.add(er);
			}
		} catch (Exception e) {
			ExceptionUtils.error(LOG, "", e);
		}
		return records;
	}

    @Override
    public void recordErrors(List<ErrorRecord> errors) throws ApmDataIndicatorException {
        try {
            PerfIndicesBuilder perfIncidesBuilder = PerfIndicesBuilder.getInstance();
            BulkRequestBuilder bulkbuilder = client.prepareBulk();
            for (ErrorRecord error : errors) {
                for (String index : perfIncidesBuilder.getErrorIndices(error)) {
                    bulkbuilder.add(client.prepareIndex(index, Scope.APMRUNNING_ERRORS.getType(), error.getId())
                            .setSource(JsonUtil.obj2json(error)));
                }
            }
            BulkResponse bulkResponse = bulkbuilder.execute().actionGet();
            if (bulkResponse.hasFailures()) {
                ExceptionUtils.error(LOG, String.format("错误信息组保存失败:%s", bulkResponse.buildFailureMessage()),
                        new Exception());
            }
        } catch (Exception e) {
            ExceptionUtils.error(LOG, String.format("错误信息组保存失败:%s", e), e);
        }

    }
    
    @Override
    public void recoredErrorDetail(List<com.broada.apm.model.ErrorDetail> errorDetails) throws IOException {
    	try {
            PerfIndicesBuilder perfIncidesBuilder = PerfIndicesBuilder.getInstance();
            BulkRequestBuilder bulkbuilder = client.prepareBulk();
            for (com.broada.apm.model.ErrorDetail error : errorDetails) {
                for (String index : perfIncidesBuilder.getErrorDetailIndices(error)) {
                    try {
						bulkbuilder.add(client.prepareIndex(index, Scope.APMRUNNING_ERROR_DETAIl.getType(), error.getId())
						        .setSource(JsonUtil.obj2json(error)));
					} catch (Exception e) {
					}
                }
            }
            BulkResponse bulkResponse = bulkbuilder.execute().actionGet();
            if (bulkResponse.hasFailures()) {
                ExceptionUtils.error(LOG, String.format("错误信息组保存失败:%s", bulkResponse.buildFailureMessage()),
                        new Exception());
            }
        } catch (Exception e) {
            ExceptionUtils.error(LOG, String.format("错误信息组保存失败:%s", e), e);
        }
    }

	@Override
	public List<ErrorRecordView> queryErrorRedords(String applicationId, SearchCondition searchCondition)
			throws ApmDataIndicatorException {
		List<ErrorRecordView> result = new ArrayList<ErrorRecordView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("错误交易查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getErrorIndices(applicationId, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_ERRORS.getType()).setPostFilter(queryBuilder)
					.setFrom(searchCondition.getStartRecord()).setSize(searchCondition.getPageSize());
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response != null) {
				for (SearchHit hit : response.getHits()) {
					String source = hit.sourceAsString();
					result.add((ErrorRecordView) JsonUtil.json2obj(source, ErrorRecordView.class));
				}
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}
	
	@Override
	public List<PerformanceView> queryAggregationTermsErrorRedord(String applicationId, SearchCondition searchCondition)
			throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("错误交易查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getErrorIndices(applicationId, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;
			SearchRequestBuilder searchBuilder = client.prepareSearch(); // {}
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_ERRORS.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			Aggregations aggs = response.getAggregations();
			List<Map<String, Object>> aggRows = AggregationUtil.parseMultiTermsAggregations(aggs);
			for (Map<String, Object> map : aggRows) {
				PerformanceView er = JsonUtil.map2obj(map, PerformanceView.class);
				result.add(er);
			}
		} catch (Exception e) {
			ExceptionUtils.error(LOG, "", e);
		}
		return result;
	}

	@Override
	public List<PerformanceView> queryErrorDetail(String appId, SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("错误交易查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getErrorDetailIndices(appId, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_ERROR_DETAIl.getType()).setPostFilter(queryBuilder)
					.setFrom(searchCondition.getStartRecord()).setSize(searchCondition.getPageSize());
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response != null) {
				for (SearchHit hit : response.getHits()) {
					String source = hit.sourceAsString();
					result.add(new PerformanceView(JsonUtil.json2map(source)));
				}
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

}
